<?php

namespace App\Models\Scm;

use Dcat\Admin\Traits\HasDateTimeFormatter;
use Dcat\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
use Spatie\EloquentSortable\Sortable;


/**
 * 智慧社区组织模型类
 *
 * 使用 ModelTree
 *
 * @table scm_orgs
 */
class Org extends Model
{
    use HasFactory, ModelTree, SoftDeletes, HasDateTimeFormatter;

    /**
     * table name
     * @var string
     */
    protected $table = 'scm_orgs';

    protected $fillable = [
        'name',
        'parent_id',
        'sort',
        'relation_class_name',
    ];

    /**
     * json <=> array
     * @var string[]
     */
    protected $casts = [
        'extra_data' => 'array',
        'parent_ids' => 'array',
        'children_ids' => 'array',
        'paths' => 'array',
        'paths_index' => 'array',
    ];

    /**
     * parent column
     * @var string
     */
    public $parentColumn = 'parent_id';

    /**
     * order column
     * @var string
     */
    public $orderColumn = 'sort';

    /**
     * title column
     * @var string
     */
    public $titleColumn = 'name';

    /**
     * depth column
     * @var string
     */
    public $depthColumn = 'depth';

    /**
     * status enabled
     */
    const STATUS_ENABLED = 1;

    /**
     * status disabled
     */
    const STATUS_DISABLED = 0;

    /**
     * status tested
     */
    const STATUS_TESTED = 2;

    /**
     * relation class company
     */
    const RELATION_CLASS_NAME_COMPANY = Company::class;

    /**
     * relation class company
     */
    const RELATION_CLASS_NAME_COMMUNITY = Community::class;

    /**
     * relation class building
     */
    const RELATION_CLASS_NAME_BUILDING = Building::class;

    public static function staticEnums(): Collection|array
    {
        return [
            'status' => [
                [
                    'id' => self::STATUS_ENABLED,
                    'text' => '启用',
                    'label' => 'success',
                    'sort' => 1,
                    'default' => true,
                ],
                [
                    'id' => self::STATUS_DISABLED,
                    'text' => '停用',
                    'label' => 'danger',
                    'sort' => 2,
                    'default' => false,
                ],
                [
                    'id' => self::STATUS_TESTED,
                    'text' => '测试',
                    'label' => 'warning',
                    'sort' => 3,
                    'default' => false,
                ],
            ],
            'relation_class_name' => [
                [
                    'id' => self::RELATION_CLASS_NAME_COMPANY,
                    'text' => '公司',
                    'sort' => 1,
                    'default' => true,
                ],
                [
                    'id' => self::RELATION_CLASS_NAME_COMMUNITY,
                    'text' => '项目',
                    'sort' => 2,
                    'default' => true,
                ],
                [
                    'id' => self::RELATION_CLASS_NAME_BUILDING,
                    'text' => '建筑',
                    'sort' => 3,
                    'default' => true,
                ],
            ],
        ];
    }


    /**
     * 获取全部子节点
     * @param int $parentId int 父节点ID
     * @param array|null $keys array 筛选key数组 [$self->getKeyName(),$self->getTitleColumn(),$self->getParentColumn(),$self->getOrderColumn()]
     * @param bool $isTree
     * @param string $childrenKey 子节点名称
     * @return Collection
     */
    public static function childNodes(int $parentId = 0, array|null $keys = [], bool $isTree = false, string $childrenKey = 'children'): Collection
    {
        $self = new static();
        $keys = \collect($keys);
        if ($keys->isEmpty()) {
            $keys->add($self->getKeyName())->add($self->getTitleColumn())->add($self->getParentColumn())->add($self->getOrderColumn());
            if ($isTree) {
                $keys->add($childrenKey);
            }
        }
        $branch = \collect();
        $nodes = $self->allNodes();
        foreach ($nodes as $node) {
            if ($node[$self->getParentColumn()] == $parentId) {
                $childNodes = $self::childNodes($node[$self->getKeyName()], $keys->unique()->toArray(), $isTree, $childrenKey);
                if ($isTree) {
                    $node[$childrenKey] = $childNodes;
                } else {
                    $branch = $branch->merge($childNodes);
                }

                $branch->add(\collect($node)->only($keys));
            }
        }
        return $branch;
    }


    /**
     * 获取全部父节点
     * @param int $childId 子节点ID
     * @param array|null $keys array 筛选key数组 [$self->getKeyName(),$self->getTitleColumn(),$self->getParentColumn(),$self->getOrderColumn()]
     * @param bool $isTree 树形视图显示
     * @param string $parentsKey 父节点名称
     * @return Collection
     */
    public static function parentNodes(int $childId = 0, array|null $keys = [], bool $isTree = false, string $parentsKey = 'parents'): Collection
    {
        $self = new static();
        $keys = \collect($keys);
        if ($keys->isEmpty()) {
            $keys->add($self->getKeyName())->add($self->getTitleColumn())->add($self->getParentColumn())->add($self->getOrderColumn());
            if ($isTree) {
                $keys->add($parentsKey);
            }
        }
        $branch = \collect();
        $nodes = $self->allNodes();
        foreach ($nodes as $node) {
            if ($node[$self->getKeyName()] == $childId) {
                $parentNodes = $self::parentNodes($node[$self->getParentColumn()], $keys->unique()->toArray(), $isTree, $parentsKey);
                if ($isTree) {
                    $node[$parentsKey] = $parentNodes;
                } else {
                    $branch = $branch->merge($parentNodes);
                }
                $branch->add(\collect($node)->only($keys->unique()->toArray()));
            }
        }
        return $branch;
    }

    /**
     * 更新排序
     * @param int $parentId 父节点ID
     * @return void
     */
    public static function extendSaveOrder(int $parentId = 0): void
    {
        Org::saveOrder(
            Org::childNodes($parentId, ['id', 'children'], true)->toArray()
        );
    }

    public function relation_class_instance(): HasOne
    {
        return $this->hasOne($this->relation_class_name, 'org_id', 'id');
    }

    public function refreshPaths($id = 0): bool
    {
        $model = $this;
        if ($id) {
            $model = Org::query()->where('id', '=', $id)->limit(1)->first();
        }
        if ($model->id) {
            $childNodes = Org::childNodes($model->id)->sortBy($model->getOrderColumn());
            $parentNodes = Org::parentNodes($model->parent_id)->sortBy($model->getOrderColumn());
            $model->children_ids = $childNodes->pluck([$model->getKeyName()])->toArray();
            $model->parent_ids = $parentNodes->pluck([$model->getKeyName()])->toArray();
            $model->paths = $parentNodes->pluck([$model->getTitleColumn()])->add($model->name)->toArray();
            $model->paths_index = \collect($model->paths)->join('->');
            return $model->update();
        }
        return false;
    }

    public static function extendRefreshPaths($id = 0, $isRecursively = false): bool
    {
        \request()->replace([]);
        $model = Org::query()->where('id', '=', $id)->limit(1)->first();
        if (!$model) {
            return false;
        }
        if (\optional($model)->id) {
            $childNodes = Org::childNodes($model->id)->sortBy($model->getOrderColumn());
            $parentNodes = Org::parentNodes($model->parent_id)->sortBy($model->getOrderColumn());

            $model->children_ids = $childNodes->pluck([$model->getKeyName()])->toArray();
            $model->parent_ids = $parentNodes->pluck([$model->getKeyName()])->toArray();
            $model->paths = $parentNodes->pluck([$model->getTitleColumn()])->add($model->name)->toArray();
            $model->paths_index = \collect($model->paths)->join('->');
            if ($model->update()) {
                if ($isRecursively) {
                    foreach ($childNodes->where('id', '<>', $id)->pluck('id') as $childId) {
                        self::extendRefreshPaths($childId, false);
                    }
                    foreach ($parentNodes->pluck('id') as $parentId) {
                        self::extendRefreshPaths($parentId, false);
                    }
                }
                return true;
            }
        }
        return false;
    }

    public function refreshRelationClassInstance()
    {
        $model = $this;
        if (\optional($model->id)) {
            if (!\optional($model)->relation_class_instance && \str(\optional($model)->relation_class_name)->isNotEmpty()) {
                $relationClassName = $model->relation_class_name;
                $relationClassInstance = new $relationClassName();
                $relationClassInstance->org_id = $model->id;
                $relationClassInstance->name = $model->name;
                return $relationClassInstance->save();
            }
        }
        return false;
    }

    public static function extendRefreshRelationClassInstance($id = 0): bool
    {
        $model = Org::query()->where('id', '=', $id)->limit(1)->first();
        if (!$model) {
            return false;
        }
        if (\optional($model)->id) {
            if (!\optional($model)->relation_class_instance && \str(\optional($model)->relation_class_name)->isNotEmpty()) {
                $relationClassName = $model->relation_class_name;
                $relationClassInstance = new $relationClassName();
                $relationClassInstance->org_id = $model->id;
                $relationClassInstance->name = $model->name;
                return $relationClassInstance->save();
            }
        }
        return false;
    }


}
